﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Gollie.Invoice
{
	public class InvoiceCalculator
	{
		InvoiceData invoiceData = InvoiceData.Instance;
		FeeCollection fees;
		int feeIndex = 0;
		uint vendorId;

		public InvoiceCalculator(uint vendorId)
		{
			this.fees = invoiceData.GetFees(vendorId);
			this.vendorId = vendorId;
			this.NumberFeeBelowMinimum = 0;
			this.CorrectionFeeBelowMinimum = 0;
			this.TotalDeposit = 0;
			this.NetFee = 0;

			this.TotalDiscount = 0; //Future use...?

			this.InvoiceItems = new InvoiceItemCollection();
		}

		public void AddDeposit(decimal deposit, DateTime paydate)
		{
			decimal bandWith = this.fees[feeIndex].UpperBound - (feeIndex > 0 ? this.fees[feeIndex - 1].UpperBound : 0);
			decimal upperbound = this.fees[feeIndex].UpperBound;
			decimal fee = 0;
			decimal correction = 0;

			while (TotalDeposit + deposit > upperbound)
			{
				decimal percentage = this.fees[feeIndex].Percentage;
				decimal oldBandWithDeposit = upperbound - TotalDeposit;
				fee += oldBandWithDeposit * percentage / 100;

				this.InvoiceItems.Add(new InvoiceItem { Deposit = bandWith, Fee = bandWith * percentage / 100, Percentage = percentage });

				deposit -= oldBandWithDeposit;
				TotalDeposit += oldBandWithDeposit;

				feeIndex++;
				bandWith = this.fees[feeIndex].UpperBound - (feeIndex > 0 ? this.fees[feeIndex - 1].UpperBound : 0);
				upperbound = this.fees[feeIndex].UpperBound;
			}

			fee += deposit * this.fees[feeIndex].Percentage / 100;

			if (fee < invoiceData.MinimumFeePerDeposit)
			{
				NumberFeeBelowMinimum++;
				correction = invoiceData.MinimumFeePerDeposit - fee;
			}

			CorrectionFeeBelowMinimum += correction;

			TotalDeposit += deposit;

			GrossFee += fee;
		}

		public void FinalizeCalculation()
		{
			decimal upperBound = (feeIndex > 0 ? this.fees[feeIndex - 1].UpperBound : 0);
			if (TotalDeposit > upperBound)
			{
				decimal remainingDeposit = TotalDeposit - upperBound;

				this.InvoiceItems.Add(new InvoiceItem { Deposit = remainingDeposit, Fee = remainingDeposit * this.fees[feeIndex].Percentage / 100, Percentage = this.fees[feeIndex].Percentage });
			}

			GrossFee += CorrectionFeeBelowMinimum;
			NetFee = GrossFee - TotalDiscount;

			//prevent rounding errors
			if (NetFee < 0)
				NetFee = 0;

			TotalVat = NetFee * invoiceData.VatPercentage / 100;
		}

		public decimal TotalVat
		{
			get;
			private set;
		}

		public decimal CorrectionFeeBelowMinimum
		{
			get;
			private set;
		}

		public int NumberFeeBelowMinimum
		{
			get;
			private set;
		}

		public decimal TotalDeposit
		{
			get;
			private set;
		}

		public decimal GrossFee
		{
			get;
			private set;
		}

		public decimal NetFee
		{
			get;
			private set;
		}

		public decimal TotalDiscount
		{
			get;
			private set;
		}

		public InvoiceItemCollection InvoiceItems
		{
			get;
			private set;
		}
	}
}
